#ifndef __CAP_VALIDATOR_H__
#define __CAP_VALIDATOR_H__

#include <ode/ode.h>
#include <boost/thread.hpp>
#include <math.h>
#include "Validator.hpp"
#include "common.hpp"

#define CAP_VALIDATOR_PI 3.14159265

#define DIM_ASTA	4
#define I_STATE_MAX	500
#define I_STATE_MIN -500
#define MAX_CONTROL	10.0

/** \class CaP_ValidatorException
 *  \brief Eccezioni lanciate dalla classe CaP_Validator. Contiene solo un messaggio di errore.
 */
class CaP_ValidatorException : public ValidatorException
{
    public:
    CaP_ValidatorException(char *mess) : ValidatorException(mess) {};
};

class CaP_Validator : public Validator{
#ifdef __DIST_CAPVALIDATOR_H__
	friend class DistCaPValidator;
#endif

	public:
	//! Specifica del comportamento a fronte di errori durante la lettura dei settings
    enum error_hand_type{
        ERR_IGNORE,     //!< Ignora gli errori quando possibile
        ERR_HALT        //!< Lancia ArchValidatorException a fronte di qualsiasi errore
    };

		boost::shared_ptr<boost::thread> m_thread;
	
	dWorldID		world;
	dSpaceID		space;
	dBodyID			sferaBody,boxBody;
	dGeomID			sferaGeom,boxGeom;
	dMass			sferaMass,boxMass;
	dJointGroupID	contactgroup;
	dJointID		cerniera1, motore;
	float			simTime;

	unsigned int	max_score;
	unsigned int	n_eval;
	unsigned int	simSteps;
	float			minStartAngle, maxStartAngle;

	//Variabili di stato per il controllore PID di prova...
	dReal D_state;
	dReal I_state;
	//dReal I_state_max = 500;
	//dReal I_state_min = -500;

	//void nearCallback (void *data, dGeomID o1, dGeomID o2);
	dReal PID(dReal angolo);
	void resetControllo() {D_state = 0; I_state = 0;}
	dReal simLoop(int pause);
	void resetSimulation(dReal angolo);
	unsigned int valutaSingleRun(Individuo &Ind);
	//void destroyObjects();

	//CaP_Validator();


	/** Legge i settings ed effettua le inizializzazioni necessarie
     *
     *  I parametri necessari per il costruttore sono:
     *  \arg \c train_set:
     *
     *  \param[in] settings Contiene tutti i parametri necessari per l'inizializzazione
     *  \param[in] eht Specifica il comportamento a fronte di un errore nella lettura dei parametri
     */
    CaP_Validator(GAmodSettings &settings,error_hand_type eht = CaP_Validator::ERR_HALT) throw(CaP_ValidatorException);

    /** Dealloca tutte le immagini eventualmente caricate
     */
    ~CaP_Validator();

    unsigned int valuta_pop(Popolazione *pop,stat_generation sg=Validator::STAT_ALL) throw(CaP_ValidatorException) ;
    unsigned int valuta_pop(Popolazione *pop,int eval_from = 0, int eval_to = 0,stat_generation sg=Validator::STAT_ALL) throw(CaP_ValidatorException);


    /** Restituisce le statistiche del valutatore
     *
     *  \param[out] settings Contenitore delle statistiche da ritornare
     */
    int getValutatorStats(GAmodSettings &settings) throw(CaP_ValidatorException) {return 0;};

    //! Ritorna il massimo punteggio ottenibile
    unsigned int getMaxScore() {return this->max_score;};

	unsigned int snapIndividuo(Individuo &Ind,char *path) throw(CaP_ValidatorException);
	//unsigned int print_single_run(Individuo &Ind, int *map, int *food, char *path) throw(EHW_Exception);
	
	private:
	Popolazione* evpop;
	//multithread function
	unsigned int valuta_pop_mt();
};

#endif
